#pragma once 

#include <stdio.h>
#include <string.h>
#include <iostream>

#include <jsoncpp/json/json.h>

#define TCP_PORT 17878
#define UDP_PORT 17878

#define UDP_MAX_DATA_LEN 10240

//双方约定TCP数据格式(注册和登录)

//一、注册请求的数据格式
//1.昵称
//2.学校
//3.用户密码
//客户端向服务端严格按照RegisterInfo格式传输注册数据
struct RegisterInfo
{
    RegisterInfo() //构造
    {
         //为什么要memset初始化，因为当密码长度小于20时，可能在读字符数组时读到一些未定义的值
        memset(nick_name_, '\0', sizeof(nick_name_));
        memset(school_, '\0', sizeof(school_));
        memset(passwd_, '\0', sizeof(passwd_));
    }

    char nick_name_[20];
    char school_[20];
    char passwd_[20];
};


//二、登录请求的数据格式
//1.用户ID
//2.密码
struct LoginInfo
{
    LoginInfo() //构造
    {
        memset(passwd_, '\0', sizeof(passwd_)); 
        //为什么要memset初始化，因为当密码长度小于20时，可能在读字符数组时读到一些未定义的值
    }

    uint32_t id_;
    char passwd_[20];
};


//三、服务端给客户端回复应答的数据格式
//1.当前的状态(注册返回的状态、登陆返回的状态)
//2.返回用户ID，类似注册完毕之后返回的QQ号
struct ReplyInfo
{
    int resp_status_; //返回状态
    uint32_t id_;  //返回用户ID
};

//客户端就可以根据枚举值来判断自己是注册成功了还是注册失败了，登录成功了还是登录失败了。
enum Status  //状态用枚举来表示resp_status_，int resp_status_;
{
    REGISTER_FAILED = 0,
    REGISTER_SUCCESS, 
    LOGIN_FAILED,
    LOGIN_SUCCESS,
    ONLINE
};


//四、如何标识当前的请求是注册请求还是登录请求
//1.对于每一种请求，在tcp层面都会发送两个tcp包
// 第一个tcp包，发送一个字节，标识请求是"注册"还是"登录"
// 第二个tcp包，发送具体的"注册"或者"登录"的请求数据
enum ResqType
{
    REGISTER_RESQ = 0,
    LOGIN_RESQ
};


//双方约定UDP数据格式(发消息)
//Json数据格式
class UdpMsg
{
    public:
        UdpMsg()
        {}

        ~UdpMsg()
        {}

        //序列化：将对象转换成为二进制的过程
        //        为了将二进制通过网络接口传输到对端
        void serialize(std::string* msg)
        {
            Json::Value json_msg; //Json::Value是jsoncpp 中最基本、最重要的类，用于表示各种类型的对象，Value类的对象代表一个Json值

            json_msg["nick_name"] = nick_name_;
            json_msg["school"] = school_;
            json_msg["user_id"] = user_id_;
            json_msg["msg"] = msg_;

            Json::FastWriter writer;
            *msg = writer.write(json_msg);//将内存中的Value对象转换成为Json文档，输出到文件或者是字符串中
        }

        //反序列化：将二进制转换成为对象的过程
        //          为了将从网络当中接收的数据，序列化成为我们认识的字符串
        void deserialize(std::string msg) //反序列化传进来的就是string对象
        {
            Json::Reader reader;//Json::Reader 是用于读取的，说的确切点，是用于将字符串转换为 Json::Value 对象的，主要函数有parse
            Json::Value val;
            reader.parse(msg, val);
            nick_name_ = val["nick_name"].asString();
            school_ = val["school"].asString();
            user_id_ = val["user_id_"].asUInt();
            msg_ = val["msg"].asString();
        }

    public:
        std::string nick_name_;
        std::string school_;
        uint32_t user_id_;
        std::string msg_;
};
